﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace platformEditor
{
    public partial class frmMain : Form
    {
        private Boolean configChanged;

        public frmMain()
        {
            InitializeComponent();
            pbPlatform.Image = new Bitmap(pbPlatform.Width, pbPlatform.Height);
            resetData();
        }

        private void resetData()
        {
            //A
            nudATheta.Value = 0;
            nudAX.Value = -250;
            nudAY.Value = -250;
            nudAZ.Value = -250;
            //B
            nudBTheta.Value = 0;
            nudBX.Value = 250;
            nudBY.Value = -250;
            nudBZ.Value = -250;
            //C
            nudCTheta.Value = 0;
            nudCX.Value = 250;
            nudCY.Value = 250;
            nudCZ.Value = -250;
            //D
            nudDTheta.Value = 0;
            nudDX.Value = -250;
            nudDY.Value = 250;
            nudDZ.Value = -250;
            updateImg(null, null);
            configChanged = false;
        }

        private Single mmToPixel(Decimal mm)
        {
            return (Single)mm / 2f;
        }

        private Double toRadians(Double angle)
        {
            return ((Double)angle * Math.PI / 180.0);
        }

        private Double toDegrees(Double angle)
        {
            return angle * 180.0 / Math.PI;
        }

        private Double Angle(Double sin, Double cos)
        {
            if (sin >= 0 && cos >= 0)
            {
                //1o quadrante
                return Math.Asin(sin);
            }
            else if (sin >= 0 && cos < 0)
            {
                //2o quadrante
                return Math.Acos(cos);
            }
            else if (sin < 0 && cos < 0)
            {
                // 3o quadrante
                return Math.Asin(-sin) + Math.PI;
            }
            else
            {
                // 4o quadrante
                return Math.Asin(sin) + Math.PI * 2.0;
            }
        }

        private Single platformCenter()
        {
            return (Single)pbPlatform.Width / 2f;
        }

        private String[] splitLine(String line)
        {
            String[] ret = line.Split(new char[] { ' ' });
            if (ret.Length != 4)
            {
                throw new Exception("Arquivo de configuração inválido: número de colunas = " + ret.Length);
            }
            return ret;
        }

        //FIXME: nao funfa direito
        private void parseConfig(String config)
        {
            config = config.Replace('.', ',');
            String[] lines = config.Split(new char[] { '\n' });
            String[] numbers;
            if (lines.Length != 15)
            {
                throw new Exception("Arquivo de configuração inválido: número de linhas = " + lines.Length);
            }
            //A
            numbers = splitLine(lines[0]);
            nudATheta.Value = (-(Decimal)toDegrees(Angle(-Double.Parse(numbers[1]), Double.Parse(numbers[0]))) + 360m) % 360;
            nudAX.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[1]);
            nudAY.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[2]);
            nudAZ.Value = -Decimal.Parse(numbers[3]);
            //B
            numbers = splitLine(lines[4]);
            nudBTheta.Value = (-(Decimal)toDegrees(Angle(-Double.Parse(numbers[1]), Double.Parse(numbers[0]))) + 360m) % 360;
            nudBX.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[5]);
            nudBY.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[6]);
            nudBZ.Value = -Decimal.Parse(numbers[3]);
            //C
            numbers = splitLine(lines[8]);
            nudCTheta.Value = (-(Decimal)toDegrees(Angle(-Double.Parse(numbers[1]), Double.Parse(numbers[0]))) + 360m) % 360;
            nudCX.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[9]);
            nudCY.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[10]);
            nudCZ.Value = -Decimal.Parse(numbers[3]);
            //D
            numbers = splitLine(lines[12]);
            nudDTheta.Value = (-(Decimal)toDegrees(Angle(-Double.Parse(numbers[1]), Double.Parse(numbers[0]))) + 360m) % 360;
            nudDX.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[13]);
            nudDY.Value = -Decimal.Parse(numbers[3]);
            numbers = splitLine(lines[14]);
            nudDZ.Value = -Decimal.Parse(numbers[3]);
        }

        private String generateConfig()
        {
            String ret = "";
            //A
            ret += Math.Cos(toRadians(-(Double)nudATheta.Value)) + " " + (-Math.Sin(toRadians(-(Double)nudATheta.Value))) + " 0 " + (-nudAX.Value) + "\n";
            ret += Math.Sin(toRadians(-(Double)nudATheta.Value)) + " " + (Math.Cos(toRadians(-(Double)nudATheta.Value))) + " 0 " + (-nudAY.Value) + "\n";
            ret += "0 0 1 " + (-nudAZ.Value) + "\n\n";
            //B
            ret += Math.Cos(toRadians(-(Double)nudBTheta.Value)) + " " + (-Math.Sin(toRadians(-(Double)nudBTheta.Value))) + " 0 " + (-nudBX.Value) + "\n";
            ret += Math.Sin(toRadians(-(Double)nudBTheta.Value)) + " " + (Math.Cos(toRadians(-(Double)nudBTheta.Value))) + " 0 " + (-nudBY.Value) + "\n";
            ret += "0 0 1 " + (-nudBZ.Value) + "\n\n";
            //C
            ret += Math.Cos(toRadians(-(Double)nudCTheta.Value)) + " " + (-Math.Sin(toRadians(-(Double)nudCTheta.Value))) + " 0 " + (-nudCX.Value) + "\n";
            ret += Math.Sin(toRadians(-(Double)nudCTheta.Value)) + " " + (Math.Cos(toRadians(-(Double)nudCTheta.Value))) + " 0 " + (-nudCY.Value) + "\n";
            ret += "0 0 1 " + (-nudCZ.Value) + "\n\n";
            //A
            ret += Math.Cos(toRadians(-(Double)nudDTheta.Value)) + " " + (-Math.Sin(toRadians(-(Double)nudDTheta.Value))) + " 0 " + (-nudDX.Value) + "\n";
            ret += Math.Sin(toRadians(-(Double)nudDTheta.Value)) + " " + (Math.Cos(toRadians(-(Double)nudDTheta.Value))) + " 0 " + (-nudDY.Value) + "\n";
            ret += "0 0 1 " + (-nudDZ.Value);
            return ret.Replace(',', '.');
        }

        private void drawMarker(Graphics g, Char marker, Decimal x, Decimal y, Decimal z, Decimal theta)
        {
            g.TranslateTransform(mmToPixel(x) + platformCenter(), mmToPixel(y) + platformCenter());
            g.RotateTransform((Single)theta);
            g.DrawRectangle(Pens.Black, mmToPixel(-40), mmToPixel(-40), mmToPixel(80), mmToPixel(80));
            g.DrawString(marker.ToString(), new Font("Segoe UI", 15), Brushes.Black, mmToPixel(-20), mmToPixel(-30));
            g.RotateTransform(-(Single)theta);
            g.TranslateTransform(mmToPixel(-x) - platformCenter(), mmToPixel(-y) - platformCenter());
        }

        private void updateImg(object sender, EventArgs e)
        {
            Graphics g = Graphics.FromImage(pbPlatform.Image);
            //bg
            g.FillRectangle(Brushes.White, 0, 0, pbPlatform.Width, pbPlatform.Height);
            //center
            g.FillRectangle(Brushes.Black, pbPlatform.Width / 2 - 5, pbPlatform.Height / 2 - 5, 10, 10);
            //markers
            drawMarker(g, 'A', nudAX.Value, -nudAY.Value, nudAZ.Value, nudATheta.Value);
            drawMarker(g, 'B', nudBX.Value, -nudBY.Value, nudBZ.Value, nudBTheta.Value);
            drawMarker(g, 'C', nudCX.Value, -nudCY.Value, nudCZ.Value, nudCTheta.Value);
            drawMarker(g, 'D', nudDX.Value, -nudDY.Value, nudDZ.Value, nudDTheta.Value);
            pbPlatform.Refresh();
            configChanged = true;
        }

        private void salvarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (File.Exists("platform.ini"))
            {
                if (MessageBox.Show("Arquivo de configuração já existe. Deseja substituir?", "Confirmação", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
                {
                    File.WriteAllText("platform.ini", generateConfig(), Encoding.ASCII);
                    configChanged = false;
                }
            }
            else
            {
                File.WriteAllText("platform.ini", generateConfig(), Encoding.ASCII);
                configChanged = false;
            }
        }

        private void abrirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (configChanged)
            {
                if (MessageBox.Show("Descartar as alterações nesta configuração?", "Confirmação", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                {
                    return;
                }
            }
            if (!File.Exists("platform.ini"))
            {
                MessageBox.Show("Arquivo de configuração não encontrado.", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                parseConfig(File.ReadAllText("platform.ini", Encoding.ASCII));
                configChanged = false;
            }
        }

        private void novoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (configChanged)
            {
                if (MessageBox.Show("Descartar as alterações nesta configuração?", "Confirmação", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                {
                    return;
                }
            }
            resetData();
        }

        private void sairToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (configChanged)
            {
                if (MessageBox.Show("Descartar as alterações nesta configuração?", "Confirmação", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                {
                    e.Cancel = true;
                }
            }
        }
    }
}
